import express, { Request, Response } from "express";
import { WebSocketServer, WebSocket } from "ws";
import { createServer, Server as HttpServer } from "http";
import path from "path";
import { fileURLToPath } from "url";
import { TerminalManager } from "./terminal-manager.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
 * Web UI 服务器
 * 提供静态文件服务、REST API 和 WebSocket 实时推送
 */
export class WebUIServer {
  private app: express.Application;
  private httpServer: HttpServer | null = null;
  private wss: WebSocketServer | null = null;
  private terminalManager: TerminalManager;
  private clients: Set<WebSocket> = new Set();

  constructor(terminalManager: TerminalManager) {
    this.terminalManager = terminalManager;
    this.app = express();
    this.setupMiddleware();
    this.setupRoutes();
  }

  /**
   * 设置中间件
   */
  private setupMiddleware(): void {
    // JSON 解析
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));

    // 静态文件服务
    const publicPath = path.join(__dirname, "../public");
    this.app.use(express.static(publicPath));

    // 请求日志
    this.app.use((req, res, next) => {
      if (process.env.MCP_DEBUG === "true") {
        process.stderr.write(`[WEB-UI] ${req.method} ${req.path}\n`);
      }
      next();
    });
  }

  /**
   * 设置路由
   */
  private setupRoutes(): void {
    // 主页
    this.app.get("/", (req: Request, res: Response) => {
      res.sendFile(path.join(__dirname, "../public/index.html"));
    });

    // 终端详情页
    this.app.get("/terminal/:id", (req: Request, res: Response) => {
      res.sendFile(path.join(__dirname, "../public/terminal.html"));
    });

    // REST API 端点
    this.setupApiRoutes();
  }

  /**
   * 设置 API 路由
   */
  private setupApiRoutes(): void {
    // 获取所有终端
    this.app.get("/api/terminals", async (req: Request, res: Response) => {
      try {
        const result = await this.terminalManager.listTerminals();
        res.json(result);
      } catch (error) {
        res.status(500).json({
          error: "Failed to list terminals",
          message: error instanceof Error ? error.message : String(error),
        });
      }
    });

    // 获取终端详情
    this.app.get("/api/terminals/:id", async (req: Request, res: Response) => {
      try {
        const { id } = req.params;
        if (!id) {
          res.status(400).json({ error: "Terminal ID is required" });
          return;
        }
        const session = this.terminalManager.getTerminalInfo(id);

        if (!session) {
          res.status(404).json({ error: "Terminal not found" });
          return;
        }

        res.json({
          id: session.id,
          pid: session.pid,
          shell: session.shell,
          cwd: session.cwd,
          created: session.created.toISOString(),
          lastActivity: session.lastActivity.toISOString(),
          status: session.status,
        });
      } catch (error) {
        res.status(500).json({
          error: "Failed to get terminal info",
          message: error instanceof Error ? error.message : String(error),
        });
      }
    });

    // 创建终端
    this.app.post("/api/terminals", async (req: Request, res: Response) => {
      try {
        const { shell, cwd, env } = req.body;
        const terminalId = await this.terminalManager.createTerminal({
          shell,
          cwd,
          env,
        });

        const session = this.terminalManager.getTerminalInfo(terminalId);

        res.status(201).json({
          terminalId,
          status: session?.status,
          pid: session?.pid,
          shell: session?.shell,
          cwd: session?.cwd,
        });

        // 广播新终端创建事件
        this.broadcast({
          type: "terminal_created",
          terminalId,
        });
      } catch (error) {
        res.status(400).json({
          error: "Failed to create terminal",
          message: error instanceof Error ? error.message : String(error),
        });
      }
    });

    // 读取终端输出
    this.app.get(
      "/api/terminals/:id/output",
      async (req: Request, res: Response) => {
        try {
          const { id } = req.params;
          if (!id) {
            res.status(400).json({ error: "Terminal ID is required" });
            return;
          }
          const { since, maxLines, mode } = req.query;

          const result = await this.terminalManager.readFromTerminal({
            terminalId: id,
            since: since ? parseInt(since as string) : undefined,
            maxLines: maxLines ? parseInt(maxLines as string) : undefined,
            mode: mode as any,
          });

          res.json(result);
        } catch (error) {
          res.status(400).json({
            error: "Failed to read terminal output",
            message: error instanceof Error ? error.message : String(error),
          });
        }
      },
    );

    // 写入终端输入
    this.app.post(
      "/api/terminals/:id/input",
      async (req: Request, res: Response) => {
        try {
          const { id } = req.params;
          if (!id) {
            res.status(400).json({ error: "Terminal ID is required" });
            return;
          }
          const { input, appendNewline } = req.body;

          await this.terminalManager.writeToTerminal({
            terminalId: id,
            input,
            appendNewline,
          });

          res.json({ success: true });
        } catch (error) {
          res.status(400).json({
            error: "Failed to write to terminal",
            message: error instanceof Error ? error.message : String(error),
          });
        }
      },
    );

    // 终止终端
    this.app.delete(
      "/api/terminals/:id",
      async (req: Request, res: Response) => {
        try {
          const { id } = req.params;
          if (!id) {
            res.status(400).json({ error: "Terminal ID is required" });
            return;
          }
          const { signal } = req.query;

          await this.terminalManager.killTerminal(id, signal as string);

          res.json({ success: true });

          // 广播终端终止事件
          this.broadcast({
            type: "terminal_killed",
            terminalId: id,
          });
        } catch (error) {
          res.status(400).json({
            error: "Failed to kill terminal",
            message: error instanceof Error ? error.message : String(error),
          });
        }
      },
    );

    // 获取终端统计
    this.app.get(
      "/api/terminals/:id/stats",
      async (req: Request, res: Response) => {
        try {
          const { id } = req.params;
          if (!id) {
            res.status(400).json({ error: "Terminal ID is required" });
            return;
          }
          const result = await this.terminalManager.getTerminalStats(id);
          res.json(result);
        } catch (error) {
          res.status(400).json({
            error: "Failed to get terminal stats",
            message: error instanceof Error ? error.message : String(error),
          });
        }
      },
    );
  }

  /**
   * 设置 WebSocket
   */
  private setupWebSocket(): void {
    if (!this.httpServer) return;

    this.wss = new WebSocketServer({ server: this.httpServer });

    this.wss.on("connection", (ws: WebSocket) => {
      this.clients.add(ws);

      if (process.env.MCP_DEBUG === "true") {
        process.stderr.write("[WEB-UI] WebSocket client connected\n");
      }

      ws.on("close", () => {
        this.clients.delete(ws);
        if (process.env.MCP_DEBUG === "true") {
          process.stderr.write("[WEB-UI] WebSocket client disconnected\n");
        }
      });

      ws.on("error", (error) => {
        if (process.env.MCP_DEBUG === "true") {
          process.stderr.write(`[WEB-UI] WebSocket error: ${error}\n`);
        }
      });
    });

    // 监听终端事件并广播
    this.terminalManager.on(
      "terminalOutput",
      (terminalId: string, data: string) => {
        this.broadcast({
          type: "output",
          terminalId,
          data,
        });
      },
    );

    this.terminalManager.on("terminalExit", (terminalId: string) => {
      this.broadcast({
        type: "exit",
        terminalId,
      });
    });
  }

  /**
   * 广播消息给所有客户端
   */
  private broadcast(message: any): void {
    const payload = JSON.stringify(message);
    this.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(payload);
      }
    });
  }

  /**
   * 启动服务器
   */
  async start(port: number, host?: string): Promise<void> {
    return new Promise((resolve, reject) => {
      this.httpServer = createServer(this.app);
      const serverHost = host || process.env.WEB_UI_HOST || "127.0.0.1";

      this.httpServer.listen(port, serverHost, () => {
        if (process.env.MCP_DEBUG === "true") {
          const displayHost =
            serverHost === "0.0.0.0" ? "localhost" : serverHost;
          process.stderr.write(
            `[WEB-UI] Server started on http://${displayHost}:${port}\n`,
          );
        }

        // 启动 WebSocket
        this.setupWebSocket();

        resolve();
      });

      this.httpServer.on("error", (error) => {
        reject(error);
      });
    });
  }

  /**
   * 停止服务器
   */
  async stop(): Promise<void> {
    return new Promise((resolve) => {
      // 关闭所有 WebSocket 连接
      this.clients.forEach((client) => {
        client.close();
      });
      this.clients.clear();

      // 关闭 WebSocket 服务器
      if (this.wss) {
        this.wss.close();
        this.wss = null;
      }

      // 关闭 HTTP 服务器
      if (this.httpServer) {
        this.httpServer.close(() => {
          if (process.env.MCP_DEBUG === "true") {
            process.stderr.write("[WEB-UI] Server stopped\n");
          }
          resolve();
        });
        this.httpServer = null;
      } else {
        resolve();
      }
    });
  }
}
